package cConfig

import (
	"reflect"
	"sync"

	"gitee.com/csingo/cComponents"
	"gitee.com/csingo/cLog"
)

type ConfigContainer struct {
	lock      sync.RWMutex
	instances map[string]any
	versions  map[string]string
	listeners map[string][]cComponents.ListenHandler
}

func (i *ConfigContainer) Save(instance any) bool {
	i.lock.Lock()
	defer i.lock.Unlock()

	name := instance.(cComponents.ConfigInterface).ConfigName()
	i.instances[name] = instance
	cLog.WithContext(nil, map[string]any{
		"source": "cConfig.ConfigContainer.Save",
		"name":   name,
	}, []cLog.Option{
		cLog.IncludePaths{},
	}).Trace("注入配置")

	return true
}

func (i *ConfigContainer) Get(name string) any {
	i.lock.RLock()
	defer i.lock.RUnlock()

	return i.instances[name]
}

func (i *ConfigContainer) Remove(name string) bool {
	i.lock.Lock()
	defer i.lock.Unlock()

	delete(i.instances, name)

	return true
}

func (i *ConfigContainer) Is(instance any) bool {
	return reflect.TypeOf(instance).Implements(reflect.TypeOf((*cComponents.ConfigInterface)(nil)).Elem())
}

func (i *ConfigContainer) Range(f func(instance any)) {
	i.lock.RLock()
	defer i.lock.RUnlock()

	for _, item := range i.instances {
		f(item)
	}
}

func (i *ConfigContainer) SaveVersion(name, version string) {
	i.lock.Lock()
	defer i.lock.Unlock()

	i.versions[name] = version
}

func (i *ConfigContainer) CompareVersion(name, version string) bool {
	i.lock.RLock()
	defer i.lock.RUnlock()

	if v, ok := i.versions[name]; !ok || v != version {
		return false
	}

	return true
}

func (i *ConfigContainer) IsConfigListener(instance any) bool {
	_, ok := instance.(*cComponents.ConfigListener)
	return ok
}

func (i *ConfigContainer) SaveConfigListener(listener *cComponents.ConfigListener) bool {
	i.lock.Lock()
	defer i.lock.Unlock()

	if listener == nil {
		return false
	}

	if _, ok := i.listeners[listener.ConfigName]; !ok {
		i.listeners[listener.ConfigName] = make([]cComponents.ListenHandler, 0)
	}

	i.listeners[listener.ConfigName] = append(i.listeners[listener.ConfigName], listener.Listeners...)

	return true
}

func (i *ConfigContainer) GetConfigListeners(name string) []cComponents.ListenHandler {
	i.lock.RLock()
	defer i.lock.RUnlock()

	return i.listeners[name]
}

var container = &ConfigContainer{
	lock:      sync.RWMutex{},
	instances: make(map[string]any),
	versions:  make(map[string]string),
	listeners: make(map[string][]cComponents.ListenHandler),
}
